<!DOCTYPE html>
<html>
  <head>
    <meta content="text/html; charset=UTF-8" http-equiv="content-type">
    <title>ch04-04</title>
    <link href="css/style.css" rel="stylesheet" type="text/css">
    <link rel="stylesheet" href="thumbnailviewer.css" type="text/css">
    <script src="thumbnailviewer.js" type="text/javascript">

/***********************************************
* Image Thumbnail Viewer Script- © Dynamic Drive (www.dynamicdrive.com)
* This notice must stay intact for legal use.
* Visit http://www.dynamicdrive.com/ for full source code
***********************************************/

</script> </head>
  <body>
    <div class="os1"> 4.4 属性系统 </div>
    <br>
    Qt 元对象系统最主要的功能是实现信号和槽机制，当然也有其他功能，就是支持属性系统。有些高级语言通过编译器的 __property 或者
    [property] 等关键字实现属性系统，用于提供对成员变量的访问权限，Qt 则通过自己的元对象系统支持属性访问，Qt 是基于标准 C++
    的，不需要底层编译器支持属性，Qt 本身提供了通用的跨平台的属性系统。关于属性系统可以在 Qt 助手索引里面输入“The Property
    System”，找到相应的主题文档。Qt 类库大量使用属性，通常开发基于 Qt
    的类库时，也会用到属性系统。下面我们介绍简化版的属性系统，只列举了属性系统里面几个基本的条目。<br>
    <br>
    <div class="os2"> 4.4.1 属性系统简介 </div>
    <br>
    为了保持类的封装特性，通常成员变量需要保持私有状态，而为了与其他对象协作，就需要提供相应的 get/set
    函数。如果成员变量的数值发生了变化，通常也需要提供通知（NOTIFY）信息告知相关对象，Qt 里的通知一般都是使用信号触发。set
    函数可以作为槽函数，方便接收相关对象的信号以实现自动调整，比如上一节标签控件的 setText 槽函数。set
    函数会导致成员变量数值变化，为了通知相关对象，set 函数里通常会 emit 该成员变量发生变化的信号。<br>
    属性系统也是通过元对象系统实现的，它也是需要直接或间接从 QObject 类继承，并在类的声明里需要 Q_OBJECT
    宏。下面介绍简化版的属性声明，第一类是不指明与属性相关的私有成员变量，这时必须至少提供该属性的读函数：<br>
    <div class="code">Q_PROPERTY(type name<br>
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; READ
      getFunction <br>
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [WRITE
      setFunction]<br>
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [RESET
      resetFunction]<br>
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [NOTIFY
      notifySignal] )</div>
    Q_PROPERTY()宏就是属性的声明：<br>
    <ul>
      <li>type 是指属性的类型，可以是 C++ 标准类型、类名、结构体、枚举等，name 就是属性的名字。</li>
      <li>READ 标出该属性的读函数 getFunction，Qt 属性的读函数通常省略 get 三个字母。</li>
      <li>WRITE 标出该属性的写函数 setFunction，中括号表示可选，写函数不是必须的。</li>
      <li>RESET 标出该属性的重置函数 resetFunction，重置函数将属性设为某个默认值，中括号表示可选，重置函数不是必须的。</li>
      <li>NOTIFY 标出该属性变化时发出的通知信号 notifySignal，中括号表示可选，这个信号不是必须的。</li>
    </ul>
    这仅仅列举了属性声明里简单的几行，复杂需要查阅 Qt 帮助文档。对于属性，注意 name
    仅仅是一个用于标识属性的名字，它不是实际存在的成员变量，属性系统不会自动生成成员变量，它就是虚无的名字代号（不同属性的名字不能相同）。对于属性用到的数值会存在一
    个真正的私有成员变量里面， 私有成员变量、读函数、写函数、信号等需要另外编写这些声明，对于函数还需要编写实体代码。<br>
    <br>
    上面是不明确指出私有成员变量的情形，也可以明确指出使用了哪个成员变量，这时候属性声明为：<br>
    <div class="code">Q_PROPERTY(type name<br>
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MEMBER
      memberName<br>
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [READ
      getFunction]<br>
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [WRITE
      setFunction]<br>
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [RESET
      resetFunction]<br>
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [NOTIFY
      notifySignal] )</div>
    这里的 MEMBER 标出属性使用的成员变量 memberName，其他的行与上面的声明类似。<br>
    <br>
    在明确标出属性使用的成员变量的情况下，属性的读写函数可以省略不写，Qt 的 moc
    工具会自动为成员变量生成读写代码；而重置函数、信号等需要自己声明，并编写必须的代码；如果声明了属性值变化的通知信号，那么 moc
    工具生成的写属性代码会自动触发该通知信号。<br>
    <br>
    如果希望自己的编写的类库支持 QML，那么 NOTIFY
    通知信号是必须的，一般建议把成员变量、读函数、写函数、通知信号都明确标出来，这样方便程序员阅读和使用。<br>
    <br>
    <div class="os2"> 4.4.2 普通属性示例 </div>
    <br>
    使用
    Q_PROPERTY()宏声明的其实都是声明好的普通属性，在程序编译时就已经规定好了，本小节示范普通属性的例子，下一小节示范在运行时动态添加属性。本
    小节示范为窗口类添加自定义的属性，然后从 main 函数里面设置和打印属性的值。<br>
    打开 QtCreator ，新建一个 Qt Widgets Application 项目，在新建项目的向导里填写：<br>
    ①项目名称 normalpros，创建路径 D:\QtProjects\ch04，点击下一步；<br>
    ②套件选择里面选择全部套件，点击下一步；<br>
    ③基类选择 QWidget，点击下一步；<br>
    ④项目管理不修改，点击完成。<br>
    建好项目之后，打开头文件 widget.h，添加属性的声明代码、读写函数声明、信号声明和成员变量：<br>
    <div class="code"><span style=" color:#000080;">#ifndef</span><span style=" color:#c0c0c0;">
      </span>WIDGET_H
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#define</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000080;">WIDGET_H</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QWidget&gt;</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">namespace</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800080;">Ui</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">class</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800080;">Widget</span><span style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">class</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800080;">Widget</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">:</span><span style=" color:#c0c0c0;"> </span><span style=" color:#808000;">public</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QWidget</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000080;">Q_OBJECT</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">public</span><span style=" color:#000000;">:</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">explicit</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800080;">Widget</span><span
style=" color:#000000;">(</span><span style=" color:#800080;">QWidget</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">*</span>parent<span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000080;">0</span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">~</span><span style=" font-style:italic; color:#000000;">Widget</span><span
style=" color:#000000;">();</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//声明属性</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//不直接标出成员变量的形式</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">Q_PROPERTY</span><span
style=" color:#000000;">(</span><span style=" color:#800080;">QString</span><span
style=" color:#c0c0c0;"> </span>nickName<span style=" color:#c0c0c0;"> </span>READ<span
style=" color:#c0c0c0;"> </span>nickName<span style=" color:#c0c0c0;"> </span>WRITE<span
style=" color:#c0c0c0;"> </span>setNickName<span style=" color:#c0c0c0;"> </span>NOTIFY<span
style=" color:#c0c0c0;"> </span>nickNameChanged<span style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//直接标出成员变量的形式</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">Q_PROPERTY</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">int</span><span style=" color:#c0c0c0;"> </span>count<span
style=" color:#c0c0c0;"> </span>MEMBER<span style=" color:#c0c0c0;"> </span><span
style=" color:#800000;">m_count</span><span style=" color:#c0c0c0;"> </span>READ<span
style=" color:#c0c0c0;"> </span>count<span style=" color:#c0c0c0;"> </span>WRITE<span
style=" color:#c0c0c0;"> </span>setCount<span style=" color:#c0c0c0;"> </span>NOTIFY<span
style=" color:#c0c0c0;"> </span>countChanged<span style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//标出成员变量，可以省略读写函数</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">Q_PROPERTY</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">double</span><span
style=" color:#c0c0c0;"> </span>value<span style=" color:#c0c0c0;"> </span>MEMBER<span
style=" color:#c0c0c0;"> </span><span style=" color:#800000;">m_value</span><span
style=" color:#c0c0c0;"> </span>NOTIFY<span style=" color:#c0c0c0;"> </span>valueChanged<span
style=" color:#000000;">)</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//nickName读函数声明</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">const</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QString</span><span
style=" color:#000000;">&amp;</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">nickName</span><span style=" color:#000000;">();</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//count读函数</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">int</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">count</span><span
style=" color:#000000;">();</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//value属性声明时，指出了成员变量并省略了读写函数，它的读写代码由moc工具自动生成</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//value数值被修改时，valueChanged信号会自动触发</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//自动生成的读写代码只有简单的读写功能，不能做数值有效性检查</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">signals</span><span style=" color:#000000;">:</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//三个属性数值变化时发信号</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">void</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">nickNameChanged</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">const</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QString</span><span
style=" color:#000000;">&amp;</span><span style=" color:#c0c0c0;"> </span>strNewName<span
style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">void</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">countChanged</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">int</span><span style=" color:#c0c0c0;"> </span>nNewCount<span
style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">void</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">valueChanged</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">double</span><span
style=" color:#c0c0c0;"> </span>dblNewValue<span style=" color:#000000;">);</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">public</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#808000;">slots</span><span style=" color:#000000;">:</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//写函数通常可以作为槽函数，方便与其他信号关联，自动调整数值</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//nickName写函数声明</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">void</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">setNickName</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">const</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QString</span><span
style=" color:#000000;">&amp;</span><span style=" color:#c0c0c0;"> </span>strNewName<span
style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//count写函数声明</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">void</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">setCount</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">int</span><span style=" color:#c0c0c0;"> </span>nNewCount<span
style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//value写代码由</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">moc</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">自动生成，没有写函数</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">private</span><span style=" color:#000000;">:</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">Ui</span><span
style=" color:#000000;">::</span><span style=" color:#800080;">Widget</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">*</span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//三个私有变量，对应是三个属性</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QString</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800000;">m_nickName</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">int</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800000;">m_count</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">double</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800000;">m_value</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">};</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#endif</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">//</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">WIDGET_H</span></pre>
    </div>
    上面代码声明了三个属性，首先是 nickName：<br>
    <ul>
      <li>没有直接指出其成员变量，但其实是有的；</li>
      <li>读函数为 nickName()，返回值为属性里声明的 QString 类型（引用也算的）；</li>
      <li>写函数为 setNickName()，写函数接收 QString 类型参数，并返回 void；</li>
      <li>当属性值变化时，发送 nickNameChanged 信号，信号参数里会带有新的数值。</li>
    </ul>
    属性声明里的读写函数都需要程序员自己编写，信号自己声明，并在写函数里触发。写函数 setNickName()
    的声明放到槽函数声明部分了，这样方便关联其他信号，实现自动调整属性值。虽然属性声明里没说有成员变量，但是需要自己定义一个私有变量 m_nickName
    保存属性的数值。<br>
    <br>
    第二个属性是 count：<br>
    <ul>
      <li>直接指出它对应的成员变量是 m_count；</li>
      <li>读函数是 count()，返回 int 类型；</li>
      <li>写函数是 setCount()，接收一个 int 参数，并返回 void；</li>
      <li>当属性值变化时，发送 countChanged 信号，信号参数里会带有新的数值；</li>
    </ul>
    count 属性的工作原理 nickName 属性差不多，仅仅是在声明里明确说了对应的成员变量为 m_count。<br>
    <br>
    第三个属性是 value ，这是属性声明的极简形式，读写函数都省略了，属性读写的代码由 moc
    工具自动生成。因此这种极简形式的属性，它只需要在头文件里放三行声明代码，其他所有代码都不需要：<br>
    <div class="code"><span style=" color:#800080;">&nbsp;&nbsp;&nbsp;
        Q_PROPERTY</span><span style=" color:#000000;">(</span><span style=" color:#808000;">double</span><span
        style=" color:#c0c0c0;"> </span>value<span style=" color:#c0c0c0;"> </span>MEMBER<span
        style=" color:#c0c0c0;"> </span><span style=" color:#800000;">m_value</span><span
        style=" color:#c0c0c0;"> </span>NOTIFY<span style=" color:#c0c0c0;"> </span>valueChanged<span
        style=" color:#000000;">)<br>
      </span><br>
      <span style=" color:#000000;"><span style=" color:#808000;">signals</span><span
          style=" color:#000000;">:</span><br>
      </span><span style=" color:#808000;">&nbsp;&nbsp;&nbsp; void</span><span style=" color:#c0c0c0;">
      </span><span style=" color:#000000;">valueChanged</span><span style=" color:#000000;">(</span><span
        style=" color:#808000;">double</span><span style=" color:#c0c0c0;"> </span>dblNewValue<span
        style=" color:#000000;">);<br>
      </span><br>
      <span style=" color:#808000;">private</span><span style=" color:#000000;">:<br>
      </span><span style=" color:#808000;">&nbsp;&nbsp;&nbsp; double</span><span
        style=" color:#c0c0c0;"> </span><span style=" color:#800000;">m_value</span><span
        style=" color:#000000;">;</span></div>
    除了属性声明本身的一句，就只需要声明属性值变化是的信号和私有成员变量。<br>
    <br>
    moc 工具自动生成的读写代码仅仅是代码片段（4.5 节专门讲这些代码），没有函数的，自然没有相关的槽函数，所以如果希望把写函数作为槽函数来用，就得用类
    似 count 属性的声明，并自己编读写函数的实体代码。<br>
    <br>
    头文件代码就如上编辑，下面来添加 widget.cpp 中必须的函数实体代码：<br>
    <div class="code"><span style=" color:#000080;">#include</span><span style=" color:#c0c0c0;">
      </span><span style=" color:#008000;">"widget.h"</span>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">"ui_widget.h"</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#800080;">Widget</span><span style=" color:#000000;">::</span><span
style=" color:#000000;">Widget</span><span style=" color:#000000;">(</span><span
style=" color:#800080;">QWidget</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">*</span><span style=" color:#000000;">parent</span><span
style=" color:#000000;">)</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">:</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QWidget</span><span
style=" color:#000000;">(</span><span style=" color:#000000;">parent</span><span
style=" color:#000000;">),</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">new</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800080;">Ui</span><span style=" color:#000000;">::</span><span style=" color:#800080;">Widget</span><span
style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">setupUi</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">this</span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#800080;">Widget</span><span style=" color:#000000;">::~</span><span
style=" font-style:italic; color:#000000;">Widget</span><span style=" color:#000000;">()</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">delete</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800000;">ui</span><span style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#008000;">//读函数定义</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#008000;">//读nickName数值</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">const</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800080;">QString</span><span style=" color:#000000;">&amp;</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800080;">Widget</span><span
style=" color:#000000;">::</span><span style=" color:#000000;">nickName</span><span
style=" color:#000000;">()</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">return</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800000;">m_nickName</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#008000;">//读count数值</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">int</span><span style=" color:#c0c0c0;"> </span><span style=" color:#800080;">Widget</span><span
style=" color:#000000;">::</span><span style=" color:#000000;">count</span><span
style=" color:#000000;">()</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">return</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800000;">m_count</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#008000;">//写函数，在数值发生变化是才发信号</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">void</span><span style=" color:#c0c0c0;"> </span><span style=" color:#800080;">Widget</span><span
style=" color:#000000;">::</span><span style=" color:#000000;">setNickName</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">const</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QString</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">&amp;</span><span
style=" color:#000000;">strNewName</span><span style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">if</span><span
style=" color:#000000;">(</span><span style=" color:#000000;">strNewName</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">==</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800000;">m_nickName</span><span style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#008000;">//数值没变化，直接返回</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#808000;">return</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">}</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//修改数值并触发信号</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">m_nickName</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">strNewName</span><span style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">emit</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">nickNameChanged</span><span
style=" color:#000000;">(</span><span style=" color:#000000;">strNewName</span><span
style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">void</span><span style=" color:#c0c0c0;"> </span><span style=" color:#800080;">Widget</span><span
style=" color:#000000;">::</span><span style=" color:#000000;">setCount</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">int</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">nNewCount</span><span style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">if</span><span
style=" color:#000000;">(</span><span style=" color:#000000;">nNewCount</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">==</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800000;">m_count</span><span style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#008000;">//数值没变化，直接返回</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#808000;">return</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">}</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//修改数值并触发信号</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800000;">m_count</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">nNewCount</span><span style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">emit</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">countChanged</span><span
style=" color:#000000;">(</span><span style=" color:#000000;">nNewCount</span><span
style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
    </div>
    在 widget.cpp 只需要为 nickName 和 count 两个属性添加读写函数的代码。读函数 nickName() 和 count()
    非常简 单，就是返回相应的私有成员变量数值。<br>
    对于写函数
    setNickName()里面代码，首先判断传入的参数值是否与旧的值相同，如果是一样的就不用修改，直接返回。如果新旧数值不同，那就设置成员变量为新的值，并发送数
    值发生变化的信号 nickNameChanged，并把新值作为参数放到信号里面。set 函数里其实可以顺便做一下数值的有效性检查，上面代码里省略了有效性
    检查。<br>
    对于写函数 setCount 是类似的过程，新旧数值一样就不变，不一样就修改成员变量并发信号。<br>
    <br>
    窗口类 Widget 的代码就是上面那么多。如何使用这些属性呢？我们可以编辑 main.cpp ，尝试修改和读取这些属性：<br>
    <div class="code"><span style=" color:#000080;">#include</span><span style=" color:#c0c0c0;">
      </span><span style=" color:#008000;">"widget.h"</span>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QApplication&gt;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QDebug&gt;</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">int</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000080;">main</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">int</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">argc</span><span style=" color:#000000;">,</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#808000;">char</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">*</span><span
style=" color:#000000;">argv</span><span style=" color:#000000;">[])</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QApplication</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">a</span><span style=" color:#000000;">(</span><span
style=" color:#000000;">argc</span><span style=" color:#000000;">,</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">argv</span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">Widget</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">w</span><span style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//属性读写</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//通过写函数、读函数</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">w</span><span style=" color:#000000;">.</span><span
style=" color:#000000;">setNickName</span><span style=" color:#000000;">(</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">"Wid"</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000080;">qDebug</span><span
style=" color:#000000;">()&lt;&lt;</span><span style=" color:#000000;">w</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">nickName</span><span
style=" color:#000000;">();</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">w</span><span style=" color:#000000;">.</span><span
style=" color:#000000;">setCount</span><span style=" color:#000000;">(</span><span
style=" color:#000080;">100</span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000080;">qDebug</span><span
style=" color:#000000;">()&lt;&lt;</span><span style=" color:#000000;">w</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">count</span><span
style=" color:#000000;">();</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//通过</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">setProperty()</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">函数</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">和</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">property()</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">函数</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">w</span><span style=" color:#000000;">.</span><span
style=" color:#000000;">setProperty</span><span style=" color:#000000;">(</span><span
style=" color:#008000;">"value"</span><span style=" color:#000000;">,</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000080;">2.3456</span><span
style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000080;">qDebug</span><span
style=" color:#000000;">()&lt;&lt;</span>fixed<span style=" color:#000000;">&lt;&lt;</span><span
style=" color:#000000;">w</span><span style=" color:#000000;">.</span><span style=" color:#000000;">property</span><span
style=" color:#000000;">(</span><span style=" color:#008000;">"value"</span><span
style=" color:#000000;">).</span><span style=" color:#000000;">toDouble</span><span
style=" color:#000000;">();</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//显示窗体</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">w</span><span style=" color:#000000;">.</span><span
style=" color:#000000;">show</span><span style=" color:#000000;">();</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">return</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">a</span><span style=" color:#000000;">.</span><span
style=" color:#000000;">exec</span><span style=" color:#000000;">();</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
    </div>
    属性的读写既可以使用各个属性自己的读写函数，如
    setNickName()、nickName()、setCount()、count()，也可以使用属性通用的函数：setProperty()
    写属性，property() 读属性，都是通过属性的名称来寻找特定属性实现读写。<br>
    注意由于上面的 value 属性没有声明读写函数，所以对它的读写只能靠 setProperty() 和 property()
    函数，这对通用的属性读写函数的声明如下：<br>
    <div class="code">bool QObject::​setProperty(const char * name, const
      QVariant &amp; value)</div>
    <div class="code">QVariant QObject::​property(const char * name) const</div>
    ​setProperty() 第一个参数是普通字符串，就是属性的名称，第二个参数是属性的数值，QVariant 是 Qt 定义的通用变量类型，标准
    C++ 的类型和 Qt 自己的数值类型都可以自动转为 QVariant 类的对象。<br>
    ​property() 函数以变量名的字符串作为输入参数，返回一个通用的 QVariant 对象，将 QVariant 对象转为标准类型或者 Qt
    数值类型，可以用对应的 to**** 函数，toDouble 是转为双精度浮点数，toInt 是转为整型数， toString 是转为 QString
    字符串，还有其他转换函数，详细的请查阅 QVariant 帮助文档。<br>
    <br>
    代码先添加这些，我们运行这个示例，它执行的结果会打印到输出面板，如下图所示：<br>
    <center><img src="images/ch04/ch04-04-01.png" alt="run1" width="800"></center>
    <br>
    这个例子展示属性的声明和访问，但是还有一个问题，我们在 set***
    函数里修改了属性值，应该发了值改变的信号，我们没有接收这些信号，还不知道它们真发信号还是假发信号，得验验货。<br>
    我们为这个例子添加一个 C++ 类，名字为 ShowChanges，基类为 QObject：<br>
    <center><img src="images/ch04/ch04-04-02.png" alt="class" width="800"></center>
    编辑 showchanges.h，为 valueChanged 信号添加对应的槽函数 RecvValue 声明：<br>
    <div class="code"><span style=" color:#000080;">#ifndef</span><span style=" color:#c0c0c0;">
      </span>SHOWCHANGES_H
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#define</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000080;">SHOWCHANGES_H</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QObject&gt;</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">class</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800080;">ShowChanges</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">:</span><span style=" color:#c0c0c0;"> </span><span style=" color:#808000;">public</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QObject</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000080;">Q_OBJECT</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">public</span><span style=" color:#000000;">:</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">explicit</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800080;">ShowChanges</span><span
style=" color:#000000;">(</span><span style=" color:#800080;">QObject</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">*</span>parent<span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000080;">0</span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">~</span><span style=" font-style:italic; color:#000000;">ShowChanges</span><span
style=" color:#000000;">();</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">signals</span><span style=" color:#000000;">:</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">public</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#808000;">slots</span><span style=" color:#000000;">:</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//槽函数，接收</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">value</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">变化信号</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">void</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">RecvValue</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">double</span><span
style=" color:#c0c0c0;"> </span>v<span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">};</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#endif</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">//</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">SHOWCHANGES_H</span></pre>
    </div>
    然后编辑 showchanges.cpp，为槽函数添加实体代码：<br>
    <div class="code"><span style=" color:#000080;">#include</span><span style=" color:#c0c0c0;">
      </span><span style=" color:#008000;">"showchanges.h"</span>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QDebug&gt;</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#800080;">ShowChanges</span><span style=" color:#000000;">::</span><span
style=" color:#000000;">ShowChanges</span><span style=" color:#000000;">(</span><span
style=" color:#800080;">QObject</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">*</span><span style=" color:#000000;">parent</span><span
style=" color:#000000;">)</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">:</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QObject</span><span
style=" color:#000000;">(</span><span style=" color:#000000;">parent</span><span
style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#800080;">ShowChanges</span><span style=" color:#000000;">::~</span><span
style=" font-style:italic; color:#000000;">ShowChanges</span><span style=" color:#000000;">()</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#008000;">//接收并打印</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">value</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">变化后的新值</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">void</span><span style=" color:#c0c0c0;"> </span><span style=" color:#800080;">ShowChanges</span><span
style=" color:#000000;">::</span><span style=" color:#000000;">RecvValue</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">double</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">v</span><span style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000080;">qDebug</span><span
style=" color:#000000;">()&lt;&lt;</span><span style=" color:#008000;">"RecvValue:</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">"</span><span style=" color:#000000;">&lt;&lt;</span>fixed<span
style=" color:#000000;">&lt;&lt;</span><span style=" color:#000000;">v</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
    </div>
    这个仅仅是类的代码，接收信号必须要定义一个对象，然后才能关联源头信号和接收端槽函数，下面修改 main.cpp 代码，添加接收端对象和关联函数代码：<br>
    <div class="code"><span style=" color:#000080;">#include</span><span style=" color:#c0c0c0;">
      </span><span style=" color:#008000;">"widget.h"</span>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QApplication&gt;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QDebug&gt;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">"showchanges.h"</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">int</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000080;">main</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">int</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">argc</span><span style=" color:#000000;">,</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#808000;">char</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">*</span><span
style=" color:#000000;">argv</span><span style=" color:#000000;">[])</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QApplication</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">a</span><span style=" color:#000000;">(</span><span
style=" color:#000000;">argc</span><span style=" color:#000000;">,</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">argv</span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">Widget</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">w</span><span style=" color:#000000;">;</span><span
style=" color:#c0c0c0;">   </span><span style=" color:#008000;">//源头对象</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//接收端对象</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">ShowChanges</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">s</span><span style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//关联</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QObject</span><span
style=" color:#000000;">::</span><span style=" color:#000000;">connect</span><span
style=" color:#000000;">(&amp;</span><span style=" color:#000000;">w</span><span
style=" color:#000000;">,</span><span style=" color:#c0c0c0;"> </span><span style=" color:#808000;">SIGNAL</span><span
style=" color:#000000;">(</span>valueChanged<span style=" color:#000000;">(</span><span
style=" color:#808000;">double</span><span style=" color:#000000;">)),</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">&amp;</span><span
style=" color:#000000;">s</span><span style=" color:#000000;">,</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#808000;">SLOT</span><span style=" color:#000000;">(</span>RecvValue<span
style=" color:#000000;">(</span><span style=" color:#808000;">double</span><span
style=" color:#000000;">)));</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//属性读写</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//通过写函数、读函数</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">w</span><span style=" color:#000000;">.</span><span
style=" color:#000000;">setNickName</span><span style=" color:#000000;">(</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">"Wid"</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000080;">qDebug</span><span
style=" color:#000000;">()&lt;&lt;</span><span style=" color:#000000;">w</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">nickName</span><span
style=" color:#000000;">();</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">w</span><span style=" color:#000000;">.</span><span
style=" color:#000000;">setCount</span><span style=" color:#000000;">(</span><span
style=" color:#000080;">100</span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000080;">qDebug</span><span
style=" color:#000000;">()&lt;&lt;</span><span style=" color:#000000;">w</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">count</span><span
style=" color:#000000;">();</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//通过</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">setProperty()</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">函数</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">和</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">property()</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">函数</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">w</span><span style=" color:#000000;">.</span><span
style=" color:#000000;">setProperty</span><span style=" color:#000000;">(</span><span
style=" color:#008000;">"value"</span><span style=" color:#000000;">,</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000080;">2.3456</span><span
style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000080;">qDebug</span><span
style=" color:#000000;">()&lt;&lt;</span>fixed<span style=" color:#000000;">&lt;&lt;</span><span
style=" color:#000000;">w</span><span style=" color:#000000;">.</span><span style=" color:#000000;">property</span><span
style=" color:#000000;">(</span><span style=" color:#008000;">"value"</span><span
style=" color:#000000;">).</span><span style=" color:#000000;">toDouble</span><span
style=" color:#000000;">();</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//显示窗体</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">w</span><span style=" color:#000000;">.</span><span
style=" color:#000000;">show</span><span style=" color:#000000;">();</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">return</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">a</span><span style=" color:#000000;">.</span><span
style=" color:#000000;">exec</span><span style=" color:#000000;">();</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
    </div>
    value 属性值被修改成了 2.3456，这个值一被修改，就会触发 valueChanged 信号，槽函数 RecvValue
    被自动调用，并且会接收到新数值并打印出来。运行这个修改后的示例，得到的结果如下：<br>
    <center><img src="images/ch04/ch04-04-03.png" alt="run2" width="800"></center>
    可以看到，槽函数打印的信息会在 qDebug()&lt;&lt;fixed&lt;&lt;w.property("value").toDouble();
    这行调用之前打印出来。无论使用通用的 <br>
    setProperty() 函数，还是属性自己独有的 set 函数，变化信号都会正确地发出来。<br>
    上面只接收了 valueChanged 信号，还有 nickNameChanged 信号和 countChanged
    信号没接收，这个两个信号对应的槽函数和关联函数代码作为练习，请读者自己动手完成。下面小节示范动态属性的使用。<br>
    <br>
    <div class="os2"> 4.4.3 动态属性示例</div>
    <br>
    不仅在源代码里面添加属性声明，程序运行时也可以通过 setProperty() 函数为当前类对象添加动态属性，获取动态属性的值也是用
    property() 函数。获取全部的动态属性名称列表可以通过 ​dynamicPropertyNames 函数：<br>
    <div class="code"> QList&lt;QByteArray&gt; QObject::​dynamicPropertyNames()
      const</div>
    ​dynamicPropertyNames 返回当前所有动态属性名称字符串的列表。<br>
    如果尝试用 property() 函数获取不存在的属性名的数值，那么会得到一个特殊的 QVariant 对象，这个对象处于不可用状态，这时
    QVariant 对象的 isValid() 函数返回 false。下面示范动态属性的例子。<br>
    重新打开 QtCreator ，新建一个 Qt Widgets Application 项目，在新建项目的向导里填写：<br>
    ①项目名称 dynamicpros，创建路径 D:\QtProjects\ch04，点击下一步；<br>
    ②套件选择里面选择全部套件，点击下一步；<br>
    ③基类选择 QWidget，点击下一步；<br>
    ④项目管理不修改，点击完成。<br>
    建好项目之后，Widget 类的代码不需要修改，动态属性不需要额外声明，直接在 main 函数里面使用就行了，我们编辑 main.cpp：<br>
    <div class="code"><span style=" color:#000080;">#include</span><span style=" color:#c0c0c0;">
      </span><span style=" color:#008000;">"widget.h"</span>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QApplication&gt;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QDebug&gt;</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">int</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000080;">main</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">int</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">argc</span><span style=" color:#000000;">,</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#808000;">char</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">*</span><span
style=" color:#000000;">argv</span><span style=" color:#000000;">[])</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QApplication</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">a</span><span style=" color:#000000;">(</span><span
style=" color:#000000;">argc</span><span style=" color:#000000;">,</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">argv</span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">Widget</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">w</span><span style=" color:#000000;">;</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//如果动态属性不存在，QVariant</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">对象的</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">isValid()</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">函数返回</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">false，变量不可用</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000080;">qDebug</span><span
style=" color:#000000;">()&lt;&lt;</span><span style=" color:#000000;">w</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">property</span><span
style=" color:#000000;">(</span><span style=" color:#008000;">"myValue"</span><span
style=" color:#000000;">).</span><span style=" color:#000000;">isValid</span><span
style=" color:#000000;">();</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//添加属性</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">myValue</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">w</span><span style=" color:#000000;">.</span><span
style=" color:#000000;">setProperty</span><span style=" color:#000000;">(</span><span
style=" color:#008000;">"myValue"</span><span style=" color:#000000;">,</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000080;">2.3456</span><span
style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//获取并打印</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000080;">qDebug</span><span
style=" color:#000000;">()&lt;&lt;</span><span style=" color:#000000;">w</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">property</span><span
style=" color:#000000;">(</span><span style=" color:#008000;">"myValue"</span><span
style=" color:#000000;">).</span><span style=" color:#000000;">toDouble</span><span
style=" color:#000000;">();</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//添加属性</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">myName</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">w</span><span style=" color:#000000;">.</span><span
style=" color:#000000;">setProperty</span><span style=" color:#000000;">(</span><span
style=" color:#008000;">"myName"</span><span style=" color:#000000;">,</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">"Wid"</span><span
style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//获取并打印</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000080;">qDebug</span><span
style=" color:#000000;">()&lt;&lt;</span><span style=" color:#000000;">w</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">property</span><span
style=" color:#000000;">(</span><span style=" color:#008000;">"myName"</span><span
style=" color:#000000;">).</span><span style=" color:#000000;">toString</span><span
style=" color:#000000;">();</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//获取所有动态属性名称，打印名称列表</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000080;">qDebug</span><span
style=" color:#000000;">()&lt;&lt;</span><span style=" color:#000000;">w</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">dynamicPropertyNames</span><span
style=" color:#000000;">();</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">w</span><span style=" color:#000000;">.</span><span
style=" color:#000000;">show</span><span style=" color:#000000;">();</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">return</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">a</span><span style=" color:#000000;">.</span><span
style=" color:#000000;">exec</span><span style=" color:#000000;">();</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
    </div>
    在 main 函数里，我们先尝试获取一个不存在的属性 myValue，property() 函数返回 QVariant 对象，由于属性不存在，所以
    QVariant 对象 isValid() 函数会返回 false，表明不可用状态，也就意味着该属性是不存在的。<br>
    <br>
    然后我们向窗体对象 w 添加了动态属性 myValue，并用 property() 函数获取了该属性的 QVariant
    对象，然后转成双精度浮点数打印。接着我们向窗体对象 w 添加了动态属性 myName，类似地用 property() 函数获取属性的 QVariant
    对象，然后转为字符串打印。<br>
    最后我们用窗体对象 w 的 dynamicPropertyNames() 函数获取了所有的动态属性名称列表，并打印了动态属性名称列表。<br>
    <br>
    例子修改的代码只有上面那些，例子运行的效果如下图所示：<br>
    <center><img src="images/ch04/ch04-04-04.png" alt="run" width="800"></center>
    通过在头文件声明普通的属性，可以为属性标明相关的成员变量、读函数、写函数、变化通知信号等等，而动态属性就没有这些特性，它其实就是以成对的属性名、属性值的
    形式存在，可以通过 setProperty() 和 property() 读写，仅此而已，所以动态属性应用得比较少。<br>
    <br>
    属性系统不仅可以声明普通属性和在运行时添加动态属性，还有一个衍生功能，就是为类添加一些附加信息，运行时可以查询这些附加信息，方便程序员或用户查询相关信
    息，下面学习为类添加附加信息的例子。<br>
    <br>
    <div class="os2"> 4.4.4 类的附加信息</div>
    <br>
    Qt 程序运行时可以查询当前对象的名称，我们之前 4.2.3 节用 QObject::objectName()
    函数获取过对象名称。运行时还可以查询类的信息，主要包括两种类信息，一种是基本的类信息，Qt
    类会自动生成这些信息，包括当前类名、继承树上的基类名称等；另一类是程序员手动添加的类附加信息，通过 Q_CLASSINFO()
    宏，在类的声明里添加类附加信息，比如：<br>
    <div class="code">Q_CLASSINFO("Version", "1.0.0")</div>
    附加信息也是成对的“名称-值”，不过注意 名称和值 都是普通字符串。如果希望在运行时查询类的附加信息，可以先用
    QObject::metaObject() 获取当前对象包含的元对象数据，然后使用 QMetaObject::​classInfo
    函数查询某个序号的附加信息：<br>
    <div class="code">const QMetaObject * QObject::​metaObject()
      const&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
      <span style="font-weight: bold;">[virtual]</span></div>
    <div class="code">QMetaClassInfo QMetaObject::​classInfo(int index) const</div>
    <br>
    对于基本信息，可以用 QMetaObject::className() 函数获取类名。如果要判断继承树上是否有某个基类，使用
    QObject::​inherits() 函数判断。这两个函数声明如下：<br>
    <div class="code">const char * QMetaObject::​className() const</div>
    <div class="code">bool QObject::​inherits(const char * className) const</div>
    下面示范类的附加信息例子，并顺路打印类的基本信息，判断基类名。<br>
    重新打开 QtCreator ，新建一个 Qt Widgets Application 项目，在新建项目的向导里填写：<br>
    ①项目名称 classinfo，创建路径 D:\QtProjects\ch04，点击下一步；<br>
    ②套件选择里面选择全部套件，点击下一步；<br>
    ③基类选择 QWidget，点击下一步；<br>
    ④项目管理不修改，点击完成。<br>
    建好项目之后，编辑 widget.h 头文件，添加附加信息：<br>
    <div class="code"><span style=" color:#000080;">#ifndef</span><span style=" color:#c0c0c0;">
      </span>WIDGET_H
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#define</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000080;">WIDGET_H</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QWidget&gt;</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">namespace</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800080;">Ui</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">class</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800080;">Widget</span><span style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">class</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#800080;">Widget</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">:</span><span style=" color:#c0c0c0;"> </span><span style=" color:#808000;">public</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QWidget</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000080;">Q_OBJECT</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">public</span><span style=" color:#000000;">:</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">explicit</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800080;">Widget</span><span
style=" color:#000000;">(</span><span style=" color:#800080;">QWidget</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">*</span>parent<span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000080;">0</span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">~</span><span style=" font-style:italic; color:#000000;">Widget</span><span
style=" color:#000000;">();</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//类的附加信息</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">Q_CLASSINFO</span><span
style=" color:#000000;">(</span><span style=" color:#008000;">"Version"</span><span
style=" color:#000000;">,</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">"1.0.0"</span><span
style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">Q_CLASSINFO</span><span
style=" color:#000000;">(</span><span style=" color:#008000;">"Author"</span><span
style=" color:#000000;">,</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">"Winland"</span><span
style=" color:#000000;">)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">Q_CLASSINFO</span><span
style=" color:#000000;">(</span><span style=" color:#008000;">"Site"</span><span
style=" color:#000000;">,</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">"https://lug.ustc.edu.cn/sites/qtguide/"</span><span
style=" color:#000000;">)</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">private</span><span style=" color:#000000;">:</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">Ui</span><span
style=" color:#000000;">::</span><span style=" color:#800080;">Widget</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">*</span><span style=" color:#800000;">ui</span><span
style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">};</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#endif</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">//</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">WIDGET_H</span></pre>
    </div>
    头文件里添加了三行，也就是三对“名称-值”，都是普通字符串。附加信息只需要添加到声明里，不需要其他代码，所以 widget.cpp
    文件保持原样，不修改。<br>
    下面我们在 main.cpp 里面访问窗体的附加信息和基本信息：<br>
    <div class="code"><span style=" color:#000080;">#include</span><span style=" color:#c0c0c0;">
      </span><span style=" color:#008000;">"widget.h"</span>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QApplication&gt;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QDebug&gt;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000080;">#include</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#008000;">&lt;QMetaClassInfo&gt;</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#808000;">int</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000080;">main</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">int</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">argc</span><span style=" color:#000000;">,</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#808000;">char</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">*</span><span
style=" color:#000000;">argv</span><span style=" color:#000000;">[])</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">QApplication</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">a</span><span style=" color:#000000;">(</span><span
style=" color:#000000;">argc</span><span style=" color:#000000;">,</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">argv</span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#800080;">Widget</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">w</span><span style=" color:#000000;">;</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//获取类的附加信息</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">const</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QMetaObject</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">*</span><span style=" color:#000000;">pMO</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">w</span><span style=" color:#000000;">.</span><span style=" font-style:italic; color:#000000;">metaObject</span><span
style=" color:#000000;">();</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//附加信息个数</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">int</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">nInfoCount</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">pMO</span><span style=" color:#000000;">-&gt;</span><span
style=" color:#000000;">classInfoCount</span><span style=" color:#000000;">();</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//打印所有的附加信息</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">for</span><span
style=" color:#000000;">(</span><span style=" color:#808000;">int</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">i</span><span style=" color:#000000;">=</span><span style=" color:#000080;">0</span><span
style=" color:#000000;">;</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">i</span><span
style=" color:#000000;">&lt;</span><span style=" color:#000000;">nInfoCount</span><span
style=" color:#000000;">;</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">i</span><span
style=" color:#000000;">++)</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">{</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#800080;">QMetaClassInfo</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">info</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">pMO</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">classInfo</span><span
style=" color:#000000;">(</span><span style=" color:#000000;">i</span><span style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">        </span><span style=" color:#000080;">qDebug</span><span
style=" color:#000000;">()&lt;&lt;</span><span style=" color:#000000;">info</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">name</span><span style=" color:#000000;">()&lt;&lt;</span><span
style=" color:#008000;">"\t"</span><span style=" color:#000000;">&lt;&lt;</span><span
style=" color:#000000;">info</span><span style=" color:#000000;">.</span><span style=" color:#000000;">value</span><span
style=" color:#000000;">();</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">}</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//基本信息</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000080;">qDebug</span><span
style=" color:#000000;">()&lt;&lt;</span><span style=" color:#008000;">"Class</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">Name:</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">"</span><span style=" color:#000000;">&lt;&lt;</span><span
style=" color:#000000;">pMO</span><span style=" color:#000000;">-&gt;</span><span
style=" color:#000000;">className</span><span style=" color:#000000;">();</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000080;">qDebug</span><span
style=" color:#000000;">()&lt;&lt;</span><span style=" color:#008000;">"Object</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">Name:</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">"</span><span style=" color:#000000;">&lt;&lt;</span><span
style=" color:#000000;">w</span><span style=" color:#000000;">.</span><span style=" color:#000000;">objectName</span><span
style=" color:#000000;">();</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//判断是否为基类</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000080;">qDebug</span><span
style=" color:#000000;">()&lt;&lt;</span><span style=" color:#000000;">w</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">inherits</span><span
style=" color:#000000;">(</span><span style=" color:#008000;">"QWidget"</span><span
style=" color:#000000;">);</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000080;">qDebug</span><span
style=" color:#000000;">()&lt;&lt;</span><span style=" color:#000000;">w</span><span
style=" color:#000000;">.</span><span style=" color:#000000;">inherits</span><span
style=" color:#000000;">(</span><span style=" color:#008000;">"nothing"</span><span
style=" color:#000000;">);</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#008000;">//显示窗口</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#000000;">w</span><span style=" color:#000000;">.</span><span
style=" color:#000000;">show</span><span style=" color:#000000;">();</span></pre>
      <pre style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;">    </span><span style=" color:#808000;">return</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">a</span><span style=" color:#000000;">.</span><span
style=" color:#000000;">exec</span><span style=" color:#000000;">();</span></pre>
      <pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#000000;">}</span></pre>
    </div>
    文件开头添加了 &lt;QDebug&gt; 和 &lt;QMetaClassInfo&gt; 两个头文件，QMetaClassInfo
    就是存储附加信息项的类，它有两个公开函数：name() 获取附加信息项的名称，value() 获取附加信息项的值。<br>
    在 main 函数里，定义好窗体对象 w，之后，先通过 metaObject() 函数得到一个 QMetaObject 常量指针 pMO；<br>
    通过 pMO-&gt;classInfoCount() 获知附加信息项的个数；<br>
    然后在 for 循环里枚举 pMO-&gt;classInfo(i) 信息项，打印信息项的名称和值。<br>
    <br>
    接下来是一些基本信息的获取，类的名字也是通过元对象指针获取 pMO-&gt;className()；<br>
    窗体对象名可以直接用 w.objectName() 获取；<br>
    判断窗体是否从某个基类派生，使用 inherits 函数，这个函数接收一个字符串，如果是对象的直接或间接基类名称就返回 true，否则返回 false。<br>
    <br>
    这个示例运行结果如下图所示（这里窗体的类名和对象名正好是一样的，其他情况可能不一样）：<br>
    <center><img src="images/ch04/ch04-04-05.png" alt="run" width="800"></center>
    本节大部分内容是上面这些，后面留两个练习，希望读者动手实践一下，并复习一下 C++ 类继承的多态性。下一节我们把本章最复杂的问题尝试讲解一下，就是由
    Qt 工具自动生成的代码 ui_*.h 和 moc_*.cpp 等。<br>
    <br>
    <br>
    <div class="practice">
      <table>
        <tbody>
          <tr>
            <td><img src="images/pics/practice.png" alt="tip"></td>
            <td> <b>练习</b> </td>
          </tr>
        </tbody>
      </table>
      ① 4.4.2 小节的示例留了两个信号 nickNameChanged 和 countChanged ，没有接收它们的槽函数，请仿造
      RecvValue 槽函数的写法，为这两个信号编写对应的槽函数，并实现关联，测试一下效果。<br>
      ② 修改 4.4.4 例子的代码，将原来的这句：<br>
      &nbsp;&nbsp;&nbsp; const QMetaObject *pMO = w.metaObject();<br>
      替换为新的两句：<br>
      &nbsp;&nbsp;&nbsp; QObject *pObj = &amp;w;<br>
      &nbsp;&nbsp;&nbsp; const QMetaObject *pMO = pObj-&gt;metaObject();<br>
      然后运行修改后的例子，查看结果有没有变化。注意 pObj 是 QObject 类对象指针，由于 metaObject()
      具有多态性，它实际调用的是派生类 Widget 对象的 metaObject() 函数。<br>
    </div>
    <br>
    <br>
    <br>
    <table style="text-align: left; width: 100%;" border="0" cellpadding="2" cellspacing="2">
      <tbody>
        <tr>
          <td style="width: 40%;">
            <div style="text-align: center;"><a href="ch04-03.htm"><img class="pic"
                  style="width: 32px; height: 32px;" alt="prev" src="images/pics/prev.png"></a></div>
          </td>
          <td style="width: 20%;">
            <div style="text-align: center;"><a href="contents.htm"><img class="pic"
                  style="width: 32px; height: 32px;" alt="contents" src="images/pics/contents.png"></a></div>
          </td>
          <td style="width: 40%;">
            <div style="text-align: center;"><a href="ch04-05.htm"><img class="pic"
                  style="width: 32px; height: 32px;" alt="next" src="images/pics/next.png"></a></div>
          </td>
        </tr>
      </tbody>
    </table>
  </body>
</html>
